package com.ruoyi.system.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;

import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.domain.TImageAttachment;
import com.ruoyi.system.domain.TImageReference;
import com.ruoyi.system.mapper.TImageAttachmentMapper;
import com.ruoyi.system.mapper.TImageReferenceMapper;
import com.ruoyi.system.service.IImageCleanupService;

// MinIO相关导入将在运行时解析

/**
 * 图片清理服务实现
 * 
 * @author ruoyi
 * @date 2025-01-XX
 */
@Service
public class ImageCleanupServiceImpl implements IImageCleanupService 
{
    private static final Logger log = LoggerFactory.getLogger(ImageCleanupServiceImpl.class);

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TImageAttachmentMapper imageAttachmentMapper;

    @Autowired
    private TImageReferenceMapper imageReferenceMapper;

    @Value("${easy.minio.endpoint}")
    private String endpoint;
    
    @Value("${easy.minio.accessKey}")
    private String accessKey;
    
    @Value("${easy.minio.secretKey}")
    private String secretKey;
    
    @Value("${easy.minio.bucketName}")
    private String bucketName;


    /**
     * 清理无引用的图片文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cleanupUnreferencedImages() 
    {
        log.info("开始执行图片清理任务...");
        
        try {
            // 设置任务状态为运行中
            redisCache.setCacheObject(CacheConstants.IMAGE_CLEANUP_STATUS_KEY, 
                "RUNNING", 10, TimeUnit.MINUTES);
            
            // 获取无引用的图片列表
            List<String> unreferencedImages = getUnreferencedImageList();
            log.info("发现 {} 个无引用图片文件", unreferencedImages.size());

            int cleanedCount = 0;
            for (String fileName : unreferencedImages) 
            {
                try {
                    // 从MinIO删除文件
                    Object minioClient = createMinioClient();
                    removeObjectFromMinio(minioClient, fileName);
                    
                    // 删除引用计数记录
                    imageReferenceMapper.deleteTImageReferenceByName(fileName);
                    
                    cleanedCount++;
                    log.info("成功删除无引用图片: {}", fileName);
                    
                } catch (Exception e) {
                    log.error("删除图片失败: {}, 错误: {}", fileName, e.getMessage());
                }
            }

            // 更新任务状态
            String status = String.format("完成 - 清理了 %d 个无引用图片文件", cleanedCount);
            redisCache.setCacheObject(CacheConstants.IMAGE_CLEANUP_STATUS_KEY, 
                status, 1, TimeUnit.HOURS);
            
            log.info("图片清理任务完成，共清理 {} 个文件", cleanedCount);
            return cleanedCount;
            
        } catch (Exception e) {
            log.error("图片清理任务执行失败", e);
            redisCache.setCacheObject(CacheConstants.IMAGE_CLEANUP_STATUS_KEY, 
                "FAILED: " + e.getMessage(), 1, TimeUnit.HOURS);
            return 0;
        }
    }

    /**
     * 记录图片与业务的关联关系
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void recordImageAttachment(String imageName, String businessType, String businessId, 
                                    String businessField, Long uploadUserId) 
    {
        try {
            // 1. 记录图片附件关联
            TImageAttachment attachment = new TImageAttachment();
            attachment.setImageName(imageName);
            attachment.setBusinessType(businessType);
            attachment.setBusinessId(businessId);
            attachment.setBusinessField(businessField);
            attachment.setUploadUserId(uploadUserId);
            attachment.setUploadTime(new Date());
            attachment.setIsActive(1);
            attachment.setCreateTime(new Date());
            attachment.setUpdateTime(new Date());
            
            imageAttachmentMapper.insertTImageAttachment(attachment);
            
            // 2. 增加引用计数
            TImageReference reference = imageReferenceMapper.selectTImageReferenceByName(imageName);
            if (reference != null) {
                // 增加引用计数
                imageReferenceMapper.incrementReferenceCount(imageName);
            } else {
                // 创建新的引用记录
                reference = new TImageReference();
                reference.setImageName(imageName);
                reference.setReferenceCount(1);
                reference.setLastReferencedAt(new Date());
                reference.setCreateTime(new Date());
                reference.setUpdateTime(new Date());
                imageReferenceMapper.insertTImageReference(reference);
            }
            
            log.info("记录图片关联: {} -> {}.{}.{}", imageName, businessType, businessId, businessField);
            
        } catch (Exception e) {
            log.error("记录图片关联失败: {}", e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 删除业务关联的图片
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public int deleteBusinessImages(String businessType, String businessId, String businessField) 
    {
        try {
            // 1. 查询业务关联的图片
            List<TImageAttachment> attachments = imageAttachmentMapper.selectImagesByBusiness(businessType, businessId);
            
            int deletedCount = 0;
            for (TImageAttachment attachment : attachments) 
            {
                // 如果指定了字段，只删除该字段的图片
                if (businessField != null && !businessField.equals(attachment.getBusinessField())) {
                    continue;
                }
                
                try {
                    // 2. 从MinIO删除文件
                    Object minioClient = createMinioClient();
                    removeObjectFromMinio(minioClient, attachment.getImageName());
                    
                    // 3. 减少引用计数
                    imageReferenceMapper.decrementReferenceCount(attachment.getImageName());
                    
                    // 4. 标记关联记录为无效
                    attachment.setIsActive(0);
                    attachment.setUpdateTime(new Date());
                    imageAttachmentMapper.updateTImageAttachment(attachment);
                    
                    deletedCount++;
                    log.info("删除业务图片: {} -> {}.{}.{}", 
                            attachment.getImageName(), businessType, businessId, businessField);
                    
                } catch (Exception e) {
                    log.error("删除业务图片失败: {}, 错误: {}", attachment.getImageName(), e.getMessage());
                }
            }
            
            return deletedCount;
            
        } catch (Exception e) {
            log.error("删除业务图片失败", e);
            throw e;
        }
    }

    /**
     * 删除用户关联的所有图片
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public int deleteUserImages(Long userId) 
    {
        try {
            // 1. 查询用户关联的图片
            List<TImageAttachment> attachments = imageAttachmentMapper.selectImagesByUserId(userId);
            
            int deletedCount = 0;
            for (TImageAttachment attachment : attachments) 
            {
                try {
                    // 2. 从MinIO删除文件
                    Object minioClient = createMinioClient();
                    removeObjectFromMinio(minioClient, attachment.getImageName());
                    
                    // 3. 减少引用计数
                    imageReferenceMapper.decrementReferenceCount(attachment.getImageName());
                    
                    // 4. 标记关联记录为无效
                    attachment.setIsActive(0);
                    attachment.setUpdateTime(new Date());
                    imageAttachmentMapper.updateTImageAttachment(attachment);
                    
                    deletedCount++;
                    log.info("删除用户图片: {} -> 用户ID: {}", attachment.getImageName(), userId);
                    
                } catch (Exception e) {
                    log.error("删除用户图片失败: {}, 错误: {}", attachment.getImageName(), e.getMessage());
                }
            }
            
            return deletedCount;
            
        } catch (Exception e) {
            log.error("删除用户图片失败", e);
            throw e;
        }
    }

    /**
     * 更新图片关联关系（用于修改操作）
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void updateImageAttachment(String oldImageName, String newImageName, String businessType, 
                                    String businessId, String businessField, Long uploadUserId) 
    {
        try {
            // 1. 删除旧图片的关联
            if (oldImageName != null && !oldImageName.isEmpty()) {
                // 减少旧图片的引用计数
                imageReferenceMapper.decrementReferenceCount(oldImageName);
                
                // 标记旧图片关联为无效
                imageAttachmentMapper.markImagesInactive(businessType, businessId, businessField);
                
                log.info("移除旧图片关联: {} -> {}.{}.{}", oldImageName, businessType, businessId, businessField);
            }
            
            // 2. 记录新图片的关联
            if (newImageName != null && !newImageName.isEmpty()) {
                recordImageAttachment(newImageName, businessType, businessId, businessField, uploadUserId);
                log.info("添加新图片关联: {} -> {}.{}.{}", newImageName, businessType, businessId, businessField);
            }
            
        } catch (Exception e) {
            log.error("更新图片关联失败: {}", e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 获取无引用的图片列表
     */
    @Override
    public List<String> getUnreferencedImageList() 
    {
        try {
            return imageReferenceMapper.selectUnreferencedImages();
        } catch (Exception e) {
            log.error("获取无引用图片列表失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 手动清理指定图片
     */
    @Override
    public boolean cleanupImage(String fileName) 
    {
        try {
            // 使用反射创建MinIO客户端
            Object minioClient = createMinioClient();

            // 从MinIO删除文件
            removeObjectFromMinio(minioClient, fileName);
            
            // 删除引用计数记录
            imageReferenceMapper.deleteTImageReferenceByName(fileName);
            
            log.info("手动删除图片成功: {}", fileName);
            return true;
            
        } catch (Exception e) {
            log.error("手动删除图片失败: {}, 错误: {}", fileName, e.getMessage());
            return false;
        }
    }

    /**
     * 获取清理任务状态
     */
    @Override
    public String getCleanupStatus() 
    {
        String status = redisCache.getCacheObject(CacheConstants.IMAGE_CLEANUP_STATUS_KEY);
        return status != null ? status : "未运行";
    }

    /**
     * 使用反射创建MinIO客户端
     */
    private Object createMinioClient() throws Exception 
    {
        Class<?> minioClientClass = Class.forName("io.minio.MinioClient");
        Object builder = minioClientClass.getMethod("builder").invoke(null);
        
        // 设置endpoint
        builder = builder.getClass().getMethod("endpoint", String.class).invoke(builder, endpoint);
        
        // 设置credentials
        builder = builder.getClass().getMethod("credentials", String.class, String.class)
                .invoke(builder, accessKey, secretKey);
        
        // 构建客户端
        return builder.getClass().getMethod("build").invoke(builder);
    }

    /**
     * 使用反射从MinIO删除对象
     */
    private void removeObjectFromMinio(Object minioClient, String fileName) throws Exception 
    {
        Class<?> removeObjectArgsClass = Class.forName("io.minio.RemoveObjectArgs");
        Object builder = removeObjectArgsClass.getMethod("builder").invoke(null);
        
        // 设置bucket
        builder = builder.getClass().getMethod("bucket", String.class).invoke(builder, bucketName);
        
        // 设置object
        builder = builder.getClass().getMethod("object", String.class).invoke(builder, fileName);
        
        // 构建参数
        Object args = builder.getClass().getMethod("build").invoke(builder);
        
        // 调用removeObject方法
        minioClient.getClass().getMethod("removeObject", removeObjectArgsClass).invoke(minioClient, args);
    }

    /**
     * 从MinIO获取所有图片文件
     */
    private List<String> getAllImagesFromMinio(Object minioClient) throws Exception 
    {
        List<String> images = new ArrayList<>();
        
        // 使用反射创建ListObjectsArgs
        Class<?> listObjectsArgsClass = Class.forName("io.minio.ListObjectsArgs");
        Object builder = listObjectsArgsClass.getMethod("builder").invoke(null);
        builder = builder.getClass().getMethod("bucket", String.class).invoke(builder, bucketName);
        Object args = builder.getClass().getMethod("build").invoke(builder);
        
        // 调用listObjects方法
        Object results = minioClient.getClass().getMethod("listObjects", listObjectsArgsClass)
                .invoke(minioClient, args);
        
        // 遍历结果
        if (results instanceof Iterable) {
            for (Object result : (Iterable<?>) results) {
                Object item = result.getClass().getMethod("get").invoke(result);
                boolean isDir = (Boolean) item.getClass().getMethod("isDir").invoke(item);
                
                if (!isDir) {
                    String fileName = (String) item.getClass().getMethod("objectName").invoke(item);
                    // 只处理图片文件
                    if (isImageFile(fileName)) {
                        images.add(fileName);
                    }
                }
            }
        }
        
        return images;
    }

    /**
     * 判断是否为图片文件
     */
    private boolean isImageFile(String fileName) 
    {
        if (fileName == null) return false;
        
        String lowerFileName = fileName.toLowerCase();
        return lowerFileName.endsWith(".jpg") || 
               lowerFileName.endsWith(".jpeg") || 
               lowerFileName.endsWith(".png") || 
               lowerFileName.endsWith(".gif") || 
               lowerFileName.endsWith(".bmp") || 
               lowerFileName.endsWith(".webp");
    }
}
